package spring.data.jpa.config;

import javax.persistence.Entity;

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.beans.factory.xml.XmlReaderContext;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.data.config.ConfigurationUtils;
import org.springframework.data.repository.config.XmlRepositoryConfigurationSource;
import org.springframework.data.util.Streamable;
import org.springframework.util.Assert;
import org.w3c.dom.Element;

public class SimpleXmlRepositoryConfigurationSource extends XmlRepositoryConfigurationSource {

    private Environment environment;

    private ResourceLoader resourceLoader;

    public SimpleXmlRepositoryConfigurationSource(Element element, ParserContext context, Environment environment) {
        super(element, context, environment);

        Assert.notNull(element, "Element must not be null!");

        XmlReaderContext readerContext = context.getReaderContext();
        this.resourceLoader = ConfigurationUtils.getRequiredResourceLoader(readerContext);
        this.environment = environment;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.springframework.data.repository.config.RepositoryConfiguration#
     * getCandidates(org.springframework.context.annotation.
     * ClassPathScanningCandidateComponentProvider)
     */
    @Override
    public Streamable<BeanDefinition> getCandidates(ResourceLoader loader) {
        ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
        scanner.setEnvironment(this.environment);
        scanner.setResourceLoader(this.resourceLoader);
        /*Entity*/
        scanner.addIncludeFilter(new AnnotationTypeFilter(Entity.class));

        getExcludeFilters().forEach(scanner::addExcludeFilter);

        return Streamable.of(() -> getBasePackages().stream()//
                .flatMap(it -> scanner.findCandidateComponents(it).stream()));
    }

}
